<script setup lang="ts">
import { Menu,DeleteFilled } from '@element-plus/icons-vue';
import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
} from '@element-plus/icons-vue'
import { useRouter, RouterView, RouterLink, useRoute } from 'vue-router'
import { onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { UploadProps, UploadUserFile } from 'element-plus'
import axios from 'axios'
import SparkMD5 from "spark-md5";
let router = useRouter()
let tz = (url: any) => {
  router.push(url)
}
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
// 切片大小定为2M
const CHUNK_SIZE = 2 * 1024 * 1024;
// 文件列表            
const fileList = ref([]);
// 创建一个ref来获取el-upload组件实例
const uploadRef = ref(null);
// 调用上传组件的sumbit方法
const onUploadSubmit = () => {
  uploadRef.value.submit();
};
// 处理上传文件信息所需要的信息
const onUpload = async ({ file }) => {
  if (!file) return;
  // 文件切片
  const chunks = createChunks(file);

  // 计算哈希值
  const hash = await calculateHash(chunks);

  // 校验是否曾经上传过
  const { data } = await verifyFile(hash, file.name);
  if (!data.shouldUpload) {
    ElMessage.warning("文件已存在");
    return;
  }
  // 上传文件切片
  await uploadChunks(chunks, file.name, hash, data.existsChunks);
  // 发送合并请求
  await mergeRequest(hash, file.name);
};
// 将文件切片
const createChunks = (file) => {
  const chunks = [];
  let cur = 0;
  while (cur < file.size) {
    chunks.push(
      file.slice(
        cur,
        cur + CHUNK_SIZE > file.size ? file.size : cur + CHUNK_SIZE
      )
    );
    cur += CHUNK_SIZE;
  }
  return chunks;
};

// 计算哈希值
const calculateHash = (chunks) => {
  // 为什么要用promise? 因为reader.onload是异步的
  return new Promise((resolve) => {
    // 文件如果太大了，每个切片都计算一遍哈希值，时间会很长
    // 所以可以这样来计算，第一及最后一个切片计算完整哈希值，其他切片只计算前2个字节、中间两个、后面2个字节
    const newChunks = [];
    const MID = CHUNK_SIZE / 2;
    chunks.forEach((chunk, index) => {
      if (index === 0 || index === chunks.length - 1) {
        newChunks.push(chunk);
      } else {
        newChunks.push(chunk.slice(0, 2));
        newChunks.push(chunk.slice(MID, MID + 2));
        newChunks.push(chunk.slice(CHUNK_SIZE - 2, CHUNK_SIZE));
      }
    });

    const spark = new SparkMD5.ArrayBuffer();
    const reader = new FileReader();
    // 由于onload是异步的所以需要用Promise，读取文件切片读取完毕就把哈希值返回出去
    reader.onload = (e) => {
      spark.append(e.target.result);
      resolve(spark.end());
    };
    // 读取文件切片 返回一个ArrayBuffer数据对象，为了就是传给 spark
    // 因为spark new SparkMD5.ArrayBuffer()创建的 只接收ArrayBuffer数据对象
    reader.readAsArrayBuffer(new Blob(newChunks));
  });
};

// 校验文件是否已经上传过
const verifyFile = async (fileHash, fileName) => {
  const res = await axios.post(
    "http://localhost:3000/verify",
    {
      fileHash,
      fileName,
      size: CHUNK_SIZE,
    },
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  );

  return res;
};

// 文件切片上传
const uploadChunks = async (chunks, fileName, hash, existsChunks) => {
  // 将切片转成formDatas数据,过滤已经上传的切片
  let formDatas = chunks.map((chunk, index) => {
    const formData = new FormData();
    formData.append("fileHash", hash);
    formData.append("chunkHash", hash + "-" + index);
    formData.append("chunk", chunk);

    return formData;
  });

  // 过滤掉已经上传的切片
  formDatas = formDatas.filter(
    (item) => !existsChunks.includes(item.get("chunkHash"))
  );

  const requestPool = [];
  let index = 0;
  while (index < formDatas.length) {
    const request = axios.post(
      "http://localhost:3000/upload",
      formDatas[index]
    );
    // 将当前请求添加到请求池中
    requestPool.push(request);
    // 请求数量加1
    index++;
  }
  await Promise.all(requestPool);
};

// 合并请求
const mergeRequest = async (fileHash, fileName) => {
  const res = await axios.post(
    "http://localhost:3000/merge",
    {
      fileHash,
      fileName,
      size: CHUNK_SIZE,
    },
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  );

  if (res.data.ok) {
    ElMessage.success("上传成功");
  }
};

function handleSuccess() {
  window.location.reload();

}

</script>

<template>
  <div class="Home">
    <div class="common-layout">
      <el-container>
        <el-header>
          <div style="display: flex; align-items: center">
            <img src="https://img1.baidu.com/it/u=4152366307,3892585726&fm=253&fmt=auto&app=138&f=JPEG?w=987&h=800"
              class="tx" />
            <h2 style="color: #000">个人网盘系统</h2>
          </div>
          <div>
            <el-button type="info" @click="tz('/user')">个人信息按钮</el-button>
          </div>
        </el-header>
        <el-container>
          <el-aside width="200px">
            <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo"
              default-active="1-1" text-color="#fff" @open="handleOpen" @close="handleClose">
              <el-sub-menu index="1">
                <template #title>
                  <el-icon>
                    <Menu />
                  </el-icon>
                  <span>文件类型</span>
                </template>
                <el-menu-item-group title="文件分组">
                  <el-menu-item index="1-1" @click="tz('/home/main')">
                    <svg t="1726387017552" class="icon" viewBox="0 0 1024 1024" version="1.1"
                      xmlns="http://www.w3.org/2000/svg" p-id="4478" width="25" height="25" style="margin-right: 5px;">
                      <path
                        d="M512 981.333333c-21.333333 0-42.666667-4.266667-64-17.066666l-298.666667-170.666667C110.933333 772.266667 85.333333 729.6 85.333333 682.666667V341.333333c0-46.933333 25.6-89.6 64-110.933333l298.666667-170.666667c38.4-21.333333 89.6-21.333333 128 0l298.666667 170.666667c38.4 21.333333 64 64 64 110.933333v341.333334c0 46.933333-25.6 89.6-64 110.933333l-298.666667 170.666667c-21.333333 12.8-42.666667 17.066667-64 17.066666z m0-853.333333c-8.533333 0-12.8 0-21.333333 4.266667l-298.666667 170.666666c-12.8 8.533333-21.333333 21.333333-21.333333 38.4v341.333334c0 17.066667 8.533333 29.866667 21.333333 38.4l298.666667 170.666666c12.8 8.533333 29.866667 8.533333 42.666666 0l298.666667-170.666666c12.8-8.533333 21.333333-21.333333 21.333333-38.4V341.333333c0-17.066667-8.533333-29.866667-21.333333-38.4l-298.666667-170.666666c-8.533333 0-12.8-4.266667-21.333333-4.266667z"
                        fill="#ffffff" p-id="4479"></path>
                      <path
                        d="M512 554.666667c-8.533333 0-12.8 0-21.333333-4.266667l-371.2-213.333333c-21.333333-12.8-25.6-38.4-17.066667-59.733334 12.8-21.333333 38.4-25.6 59.733333-17.066666l349.866667 204.8 349.866667-204.8c21.333333-12.8 46.933333-4.266667 59.733333 17.066666 12.8 21.333333 4.266667 46.933333-17.066667 59.733334l-371.2 213.333333c-8.533333 0-12.8 4.266667-21.333333 4.266667z"
                        fill="#ffffff" p-id="4480"></path>
                      <path
                        d="M512 985.6c-25.6 0-42.666667-17.066667-42.666667-42.666667V512c0-25.6 17.066667-42.666667 42.666667-42.666667s42.666667 17.066667 42.666667 42.666667v430.933333c0 25.6-17.066667 42.666667-42.666667 42.666667z"
                        fill="#ffffff" p-id="4481"></path>
                    </svg>
                    全部文件</el-menu-item>
                  <el-menu-item index="1-2" @click="tz('/home/imgfile')">
                    <svg t="1726387361478" class="icon" viewBox="0 0 1024 1024" version="1.1"
                      xmlns="http://www.w3.org/2000/svg" p-id="3378" width="25" height="25" style="margin-right: 5px;">
                      <path
                        d="M853.333333 96c40.533333 0 74.666667 34.133333 74.666667 74.666667v682.666666c0 40.533333-34.133333 74.666667-74.666667 74.666667H170.666667c-40.533333 0-74.666667-34.133333-74.666667-74.666667V170.666667c0-40.533333 34.133333-74.666667 74.666667-74.666667h682.666666zM746.666667 469.333333c-10.666667-12.8-32-14.933333-44.8-2.133333L320 808.533333l-2.133333 2.133334c-19.2 19.2-4.266667 53.333333 23.466666 53.333333h492.8c17.066667-2.133333 29.866667-14.933333 29.866667-32v-196.266667c0-6.4-2.133333-10.666667-6.4-14.933333l-108.8-149.333333-2.133333-2.133334z m-394.666667-202.666666c-46.933333 0-85.333333 38.4-85.333333 85.333333s38.4 85.333333 85.333333 85.333333 85.333333-38.4 85.333333-85.333333-38.4-85.333333-85.333333-85.333333z"
                        fill="#ffffff" p-id="3379"></path>
                    </svg>
                    图片文件</el-menu-item>
                  <el-menu-item index="1-3" @click="tz('/home/video')">
                    <svg t="1726387219074" class="icon" viewBox="0 0 1024 1024" version="1.1"
                      xmlns="http://www.w3.org/2000/svg" p-id="4674" width="25" height="25" style="margin-right: 5px;">
                      <path
                        d="M981.333333 768c-8.533333 0-17.066667 0-25.6-8.533333l-298.666666-213.333334c-12.8-8.533333-17.066667-21.333333-17.066667-34.133333 0-12.8 8.533333-25.6 17.066667-34.133333l298.666666-213.333334c12.8-8.533333 29.866667-8.533333 42.666667 0 12.8 8.533333 21.333333 21.333333 21.333333 38.4v426.666667c0 17.066667-8.533333 29.866667-21.333333 38.4-4.266667 0-12.8 4.266667-21.333333 4.266667h4.266666V768z m-226.133333-256l183.466667 132.266667V384l-183.466667 132.266667V512z"
                        fill="#ffffff" p-id="4675"></path>
                      <path
                        d="M597.333333 853.333333H128c-72.533333 0-128-55.466667-128-128V298.666667c0-72.533333 55.466667-128 128-128h469.333333c72.533333 0 128 55.466667 128 128v426.666666c0 72.533333-55.466667 128-128 128zM128 256c-25.6 0-42.666667 17.066667-42.666667 42.666667v426.666666c0 25.6 17.066667 42.666667 42.666667 42.666667h469.333333c25.6 0 42.666667-17.066667 42.666667-42.666667V298.666667c0-25.6-17.066667-42.666667-42.666667-42.666667H128z"
                        fill="#ffffff" p-id="4676"></path>
                    </svg>
                    视频文件</el-menu-item>
                  <el-menu-item index="1-4" @click="tz('/home/music')">
                    <svg t="1726387444826" class="icon" viewBox="0 0 1024 1024" version="1.1"
                      xmlns="http://www.w3.org/2000/svg" p-id="7975" width="25" height="25" style="margin-right: 5px;">
                      <path
                        d="M696.222476 399.969524h89.965714c-17.017905-132.632381-133.290667-235.227429-274.18819-235.227429-140.921905 0-257.170286 102.619429-274.18819 235.227429h89.965714v302.470095H195.047619a97.52381 97.52381 0 0 1-97.523809-97.523809v-107.422477a97.572571 97.572571 0 0 1 69.363809-93.379047l1.048381-0.292572C183.417905 232.17981 331.53219 97.52381 512 97.52381c180.443429 0 328.582095 134.631619 344.064 306.297904l1.048381 0.292572A97.572571 97.572571 0 0 1 926.47619 497.493333v107.422477a97.52381 97.52381 0 0 1-97.523809 97.523809l-63.683048-0.024381v46.153143a121.953524 121.953524 0 0 1-84.992 116.224A89.721905 89.721905 0 0 1 595.090286 926.47619h-131.632762a89.624381 89.624381 0 0 1 0-179.22438h131.632762c30.915048 0 58.172952 15.652571 74.264381 39.44838a72.850286 72.850286 0 0 0 26.721523-52.297142l0.146286-4.291048v-330.118095z"
                        p-id="7976" fill="#ffffff"></path>
                    </svg>
                    音乐文件</el-menu-item>
                  <el-menu-item index="1-5" @click="tz('/home/doxc')">
                    <svg t="1726385681129" class="icon" viewBox="0 0 1024 1024" version="1.1"
                      xmlns="http://www.w3.org/2000/svg" p-id="4288" width="25" height="25" style="margin-right: 5px;">
                      <path
                        d="M768 981.333333H256c-72.533333 0-128-55.466667-128-128V170.666667c0-72.533333 55.466667-128 128-128h341.333333c12.8 0 21.333333 4.266667 29.866667 12.8l256 256c8.533333 8.533333 12.8 17.066667 12.8 29.866666v512c0 72.533333-55.466667 128-128 128zM256 128c-25.6 0-42.666667 17.066667-42.666667 42.666667v682.666666c0 25.6 17.066667 42.666667 42.666667 42.666667h512c25.6 0 42.666667-17.066667 42.666667-42.666667V358.4L580.266667 128H256z"
                        fill="#ffffff" p-id="4289"></path>
                      <path
                        d="M853.333333 384h-256c-25.6 0-42.666667-17.066667-42.666666-42.666667V85.333333c0-25.6 17.066667-42.666667 42.666666-42.666666s42.666667 17.066667 42.666667 42.666666v213.333334h213.333333c25.6 0 42.666667 17.066667 42.666667 42.666666s-17.066667 42.666667-42.666667 42.666667zM682.666667 597.333333H341.333333c-25.6 0-42.666667-17.066667-42.666666-42.666666s17.066667-42.666667 42.666666-42.666667h341.333334c25.6 0 42.666667 17.066667 42.666666 42.666667s-17.066667 42.666667-42.666666 42.666666zM682.666667 768H341.333333c-25.6 0-42.666667-17.066667-42.666666-42.666667s17.066667-42.666667 42.666666-42.666666h341.333334c25.6 0 42.666667 17.066667 42.666666 42.666666s-17.066667 42.666667-42.666666 42.666667zM426.666667 426.666667H341.333333c-25.6 0-42.666667-17.066667-42.666666-42.666667s17.066667-42.666667 42.666666-42.666667h85.333334c25.6 0 42.666667 17.066667 42.666666 42.666667s-17.066667 42.666667-42.666666 42.666667z"
                        fill="#ffffff" p-id="4290"></path>
                    </svg>
                    文档文件</el-menu-item>
                </el-menu-item-group>
              </el-sub-menu>
              <el-menu-item index="2" @click="tz('/home/recle')">
                <el-icon><DeleteFilled /></el-icon>
                <span >回收站</span>
              </el-menu-item>
            </el-menu>
          </el-aside>
          <el-main>
            <div style="width: 100%;height: 50px;display: flex;">
              <el-upload v-model="fileList" ref="uploadRef" v-bind="$attrs" :on-success="handleSuccess" :autoUpload="false" :httpRequest="onUpload">
                <el-button type="primary">选择文件</el-button>
              </el-upload>
              <el-button type="primary" @click="onUploadSubmit" style="margin-left: 10px;">上传文件</el-button>

            </div>
            <router-view ></router-view>
          </el-main>
        </el-container>
      </el-container>
    </div>
  </div>
</template>

<style scoped>
.Home {
  width: 100%;
  height: 100vh;
  background-image: url("https://p3.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/e13b4fdccfb54e7e8ba9eb0392ccea39?from=pc");
  background-size: cover;
  background-position: center;
}

.el-container {
  height: 100vh;
}

.el-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.el-aside {
  background-color: #545C64
}

.el-main {
  background-color: rgba(255, 255, 255, 0.8);

}

.tx {
  width: 60px;
  height: 60px;
  border-radius: 50%;
}

.content {
  width: 100%;
  height: 50px;

}

ul {
  z-index: 1;
}
</style>